package pixelwaks.ctrl.impl;


import java.awt.Point;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import common.core.Tile;
import common.ctrl.IObserver;
import common.gui.IViewable;

import pixelwaks.core.impl.Game;
import pixelwaks.core.impl.Projectile;

public class ProjectileCtrl implements IObserver, Runnable {
		
	private final double TIME_SCALE = 0.0075;
	private Projectile currentProjectile;
	private boolean explosionHappened;
	private double windage;
	private Thread thread;
	private IViewable observer;
	
	@Override
	public void addView(IViewable observer) {
		
		this.observer = observer;
	}
	
	public void startAnimation(Projectile proj) {
		
		currentProjectile = proj;
		try {
			Game.lock.acquire();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		currentProjectile.setActive(true);
		explosionHappened = false;		
		windage = Game.getInstance().getWind().getWindSpeed();		
		thread = new Thread(this);
	    thread.setName("Projectile");
	    thread.start();
	}

	@Override
	public void run() {
		
		long animationDelay = 1;
		long time = System.currentTimeMillis();
		List<Point> positions = calculateAllPositions();
		Iterator<Point> itPositions = positions.iterator();
		int num = 0;
		while (currentProjectile.isActive()) {			
			try {				
				time += animationDelay;
				
				if(itPositions.hasNext()) {
					Point p = itPositions.next();
					currentProjectile.getPosition().x = p.x;
					currentProjectile.getPosition().y = p.y;
				} else {
					currentProjectile.setActive(false);										
				}
				num++;
				if(num == Game.getInstance().getBenchmarkValue()) {
					observer.updateView(null);
					num = 0;
				}
				Thread.sleep(Math.max(0,time - System.currentTimeMillis()));
			}catch (InterruptedException e) {
				System.out.println(e);
			}
		}		
		Game.lock.release();
		
		if(explosionHappened)
			Game.getInstance().getMode().explode(currentProjectile.getPosition());
		else
			Game.getInstance().getMode().nextPlayer();		
	}
	
	private List<Point> calculateAllPositions() {
		
		List<Point> positions = new ArrayList<Point>();
		int startXpos = currentProjectile.getStartPosition().x;
		int startYpos = currentProjectile.getStartPosition().y;
		int currXpos = startXpos;
		int currYpos = startYpos;		
		double time = 0.0;
		double gravity = 9.82;
		
		while(!done(currXpos, currYpos)) {
			
			double vx = currentProjectile.getVelocity() * 
			Math.cos(Math.toRadians(currentProjectile.getAngle()));			
			time += TIME_SCALE;
			double x = (vx + windage) * time;
			double y = currentProjectile.getVelocity() * time * 
				Math.sin(Math.toRadians(currentProjectile.getAngle())) - 
				((gravity * Math.pow(time, 2)) / 2);
			currXpos = (int) (x + startXpos);
			currYpos = (int) (startYpos - y);
			Point p = new Point(currXpos, currYpos);
			positions.add(p);
		}
		return positions;
	}
	
	private boolean done(int x, int y) {
		
		boolean done = false;
		
		if(hitScenery(x, y) || Game.getInstance().getMode().projectileHitSomething(new Point(x, y))) {
			explosionHappened = true;
			done = true;
		} else if(x > 1000 || x < 0 || y > 600) {
			explosionHappened = false;
			done = true;
		}		
		return done;
	}
	
	private boolean hitScenery(int x, int y) {
		
		int x2 = x / Tile.TILE_SIZE;
		int y2 = y / Tile.TILE_SIZE;
		
		if(x2 < 100 && y2 < 60 && x2 > 0 && y2 > 0)
			if(Game.getInstance().getScenery().getTiles()[y2][x2] != null) {
				return true;
			}
		return false;
	}
	
//	@Override
//	public void run() {
//		long animationDelay = 1;
//		double scaleSpeed = 0.0075;
//		long time = System.currentTimeMillis();
//		double t = 0.0;
//		List<Point> positions = calculateAllPositions();
//		while (currentProjectile.isActive()) {			
//			try {				
//				time += animationDelay;
//				t += scaleSpeed;
//				update(t);				
//				Thread.sleep(Math.max(0,time - System.currentTimeMillis()));
//			}catch (InterruptedException e) {
//				System.out.println(e);
//			}
//		}
//		if(!explosionHappened) {
//			Game.lock.release();		
//			Game.getInstance().getMode().nextPlayer();
//		}
//	}
//	
//	private boolean hitScenery() {
//		
//		int x = currentProjectile.getPosition().x / Tile.TILE_SIZE;
//		int y = currentProjectile.getPosition().y / Tile.TILE_SIZE;
//		
//		if(x < 100 && y < 60 && x > 0 && y > 0)
//			if(Game.getInstance().getScenery().getTiles()[y][x] != null) {
//				return true;
//			}
//		return false;
//	}
//
//	private void update(double time) {
//				
//		calculateNextPosition(time);
//		
//		if(hitScenery() || Game.getInstance().getMode().projectileHitSomething(currentProjectile.getPosition())) {
//			currentProjectile.setActive(false);
//			Game.lock.release();
//			explosionHappened = true;
//			Game.getInstance().getMode().explode(currentProjectile.getPosition());
//		}
//		
//		if(currentProjectile.getPosition().x > 1000 
//			|| currentProjectile.getPosition().x < 0 
//			|| currentProjectile.getPosition().y > 600)
//			currentProjectile.setActive(false);
//				
//		observer.updateView(null);
//	}
//	
//	private void calculateNextPosition(double time) {
//				
//		double gravity = 9.82;
//		
//		double vx = currentProjectile.getVelocity() * 
//					Math.cos(Math.toRadians(currentProjectile.getAngle()));
//		
//		double x = (vx + windage) * time;
//		double y = currentProjectile.getVelocity() * 
//				   time * 
//				   Math.sin(Math.toRadians(currentProjectile.getAngle())) - 
//				   ((gravity * Math.pow(time, 2)) 
//				   / 2);
//		
//		currentProjectile.getPosition().x = (int) (x + currentProjectile.getStartPosition().x);
//		currentProjectile.getPosition().y = (int) (currentProjectile.getStartPosition().y - y);
//		points.add(new Point(currentProjectile.getPosition().x, currentProjectile.getPosition().y));
//	}
}
